<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/bulma.min.css">
    <title>MeiliSearch</title>
    <style>
      em {
        color: hsl(204, 86%, 25%);
        font-style: inherit;
        background-color: hsl(204, 86%, 88%);
      }

      #results {
        max-width: 900px;
        margin: 20px auto 0 auto;
        padding: 0;
      }

      .notification {
        display: flex;
        justify-content: center;
      }

      .level-left {
        margin-right: 50px;
      }

      .document {
        padding: 20px 20px;
        background-color: #f5f5f5;
        border-radius: 4px;
        margin-bottom: 20px;
        display: flex;
      }

      .document ol {
        flex: 0 0 75%;
        max-width: 75%;
        padding: 0;
        margin: 0;
      }

      .document .image {
        max-width: 25%;
        flex: 0 0 25%;
        padding-left: 30px;
        box-sizing: border-box;
      }

      .document .image img {
        width: 100%;
      }

      .field {
        list-style-type: none;
        display: flex;
        flex-wrap: wrap;
      }

      .field:not(:last-child) {
        margin-bottom: 7px;
      }

      .attribute {
        flex: 0 0 25%;
        max-width: 25%;
        text-align: right;
        padding-right: 10px;
        box-sizing: border-box;
        text-transform: uppercase;
        color: rgba(0,0,0,.7);
      }

      .content {
        max-width: 75%;
        flex: 0 0 75%;
        box-sizing: border-box;
        padding-left: 10px;
        color: rgba(0,0,0,.9);
        overflow-wrap: break-word;
      }
    </style>
  </head>
  <body>

    <section class="hero is-light">
      <div class="hero-body">
        <div class="container">
          <h1 class="title">
            Welcome to MeiliSearch
          </h1>
          <h2 class="subtitle">
            This dashboard will help you check the search results with ease.
          </h2>

          <div class="field">
            <!-- API Key -->
            <div class="field">
              <div class="control">
                <input id="apiKey" class="input is-small" type="password" placeholder="API key (optional)">
                <div class="help">At least a private API key is required for the dashboard to access the indexes list.</div>
              </div>
            </div>
          </div>

        </div>
      </div>
    </section>

    <section class="hero container">
        <div class="notification" style="border-radius: 0 0 4px 4px;">

          <nav class="level">
            <!-- Left side -->
            <div class="level-left">
              <div class="level-item">
                <div class="field has-addons has-addons-right">
                  <p class="control">
                    <span class="select">
                      <select id="index">
                        <!-- indexes names -->
                      </select>
                    </span>
                  </p>
                  <p class="control">
                    <input id="search" class="input" type="text" autofocus placeholder="e.g. George Clooney">
                  </p>
                </div>
              </div>
            </div>

            <!-- Right side -->
            <nav class="level-right">
              <div class="level-item has-text-centered">
                <div>
                  <p class="heading">Documents</p>
                  <p id="count" class="title">25</p>
                </div>
              </div>
              <div class="level-item has-text-centered">
                <div>
                  <p class="heading">Time Spent</p>
                  <p id="time" class="title">4ms</p>
                </div>
              </div>
            </nav>
          </nav>

        </div>
    </section>

    <section>
      <ol id="results" class="content">
        <!-- documents matching resquests -->
      </ol>
    </section>
  </body>

  <script>
    function sanitizeHTMLEntities(str) {
        if (str && typeof str === 'string') {
            str = str.replace(/</g,"&lt;");
            str = str.replace(/>/g,"&gt;");
            str = str.replace(/&lt;em&gt;/g,"<em>");
            str = str.replace(/&lt;\/em&gt;/g,"<\/em>");
        }
        return str;
    }

    function httpGet(theUrl, apiKey) {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open("GET", theUrl, false); // false for synchronous request
        if (apiKey) {
          xmlHttp.setRequestHeader("x-Meili-API-Key", apiKey);
        }
        xmlHttp.send(null);
        return xmlHttp.responseText;
    }

    function refreshIndexList() {
        // TODO we must not block here
        let result = JSON.parse(httpGet(`${baseUrl}/indexes`, localStorage.getItem('apiKey')));

        if (!Array.isArray(result)) { return }

        let select = document.getElementById("index");
        select.innerHTML = '';

        for (index of result) {
            const option = document.createElement('option');
            option.value = index.uid;
            option.innerHTML = index.name;
            select.appendChild(option);
        }
    }

    let lastRequest = undefined;

    function triggerSearch() {
        var e = document.getElementById("index");
        if (e.selectedIndex == -1) { return }
        var index = e.options[e.selectedIndex].value;

        let theUrl = `${baseUrl}/indexes/${index}/search?q=${search.value}&attributesToHighlight=*`;

        if (lastRequest) { lastRequest.abort() }
        lastRequest = new XMLHttpRequest();

        lastRequest.open("GET", theUrl, true);

        if (localStorage.getItem('apiKey')) {
          lastRequest.setRequestHeader("x-Meili-API-Key", localStorage.getItem('apiKey'));
        }

        lastRequest.onload = function (e) {
            if (lastRequest.readyState === 4 && lastRequest.status === 200) {
                let sanitizedResponseText = sanitizeHTMLEntities(lastRequest.responseText);
                let httpResults = JSON.parse(sanitizedResponseText);
                results.innerHTML = '';

                let processingTimeMs = httpResults.processingTimeMs;
                let numberOfDocuments = httpResults.hits.length;
                time.innerHTML = `${processingTimeMs}ms`;
                count.innerHTML = `${numberOfDocuments}`;

                for (result of httpResults.hits) {
                    const element = {...result, ...result._formatted };
                    delete element._formatted;

                    const elem = document.createElement('li');
                    elem.classList.add("document");

                    const ol = document.createElement('ol');
                    let image = undefined;

                    for (const prop in element) {
                        // Check if property is an image url link.
                        if (typeof result[prop] === 'string') {
                            if (image == undefined && result[prop].match(/^(https|http):\/\/.*(jpe?g|png|gif)(\?.*)?$/g)) {
                                image = result[prop];
                            }
                        }

                        const field = document.createElement('li');
                        field.classList.add("field");

                        const attribute = document.createElement('div');
                        attribute.classList.add("attribute");
                        attribute.innerHTML = prop;

                        const content = document.createElement('div');
                        content.classList.add("content");
                        if (typeof (element[prop]) === "object") {
                          content.innerHTML = JSON.stringify(element[prop]);
                        } else {
                          content.innerHTML = element[prop];
                        }

                        field.appendChild(attribute);
                        field.appendChild(content);

                        ol.appendChild(field);
                    }

                    elem.appendChild(ol);

                    if (image != undefined) {
                        const div = document.createElement('div');
                        div.classList.add("image");

                        const img = document.createElement('img');
                        img.src = image;

                        div.appendChild(img);
                        elem.appendChild(div);
                    }

                    results.appendChild(elem)
                }
            } else {
                console.error(lastRequest.statusText);
            }
        };
        lastRequest.send(null);
    }

    if (!apiKey.value) {
        apiKey.value = localStorage.getItem('apiKey');
    }

    apiKey.addEventListener('input', function(e) {
        localStorage.setItem('apiKey', apiKey.value);
        refreshIndexList();
    }, false);

    let baseUrl = window.location.origin;
    refreshIndexList();

    search.oninput = triggerSearch;
    select.onchange = triggerSearch;

    triggerSearch();
  </script>
</html>
